﻿using ApiConceptsFramework.Concepts.Properties;
using ApiConceptsFramework.Contract;
using FluentAssertions;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;

namespace test.ApiConceptsFramework.Concepts.Properties
{
	[TestFixture]
	public class NumberOfParametersTests
	{
		//TODO unittests for extension methods!!

// ReSharper disable UnusedMember.Local
		class TestClass
		{
			public TestClass(string singleParam) { }

			public void NoParameters() { }
			public void SingleParameter(string p1) { }
			public string SingleReturnParameter() { return null; }
			public void SingleGenericParameter<T>() { }
			public void ThreeParameters<T1>(string p1, bool p2) { }
			public string FiveParameters<T1,T2>(string p1, bool p2) { return null; }

			public string FourInputParameters(string p1, string p2, string p3, string p4) { return null; }
			public void FiveInputParameters(string p1, string p2, string p3, string p4, string p5) { }
		}
// ReSharper restore UnusedMember.Local

		[Test, Sequential]
		public void Complexity_equals_three_per_parameter_plus_additional_cost_for_large_number(
			[Values("NoParameters", "SingleParameter", "SingleReturnParameter", "SingleGenericParameter", "ThreeParameters", "FiveParameters")] string member,
			[Values(0, 2.5f, 0, 2.5f, 15, 25)] float expectedResult)
		{
			//Arrange
			var measurableProperty = new NumberOfParameters();
			var method = typeof(TestClass).GetMember(member).First();

			//Act
			var target = new MeasurableTarget { Type = typeof(TestClass), Member = method, ReturnedValueIsUsed = true};
			var result = measurableProperty.CalculateComplexity(target, IDE.VisualStudioOrSimilar);

			//Assert
			result.Should().Be(expectedResult);
			Console.WriteLine("Complexity of " + member + " = " + result);
		}

		[Test]
		public void Complexity_can_be_calculated_for_constructor()
		{
			//Arrange
			var measurableProperty = new NumberOfParameters();
			var method = typeof(TestClass).GetConstructors().First();

			//Act
			var target = new MeasurableTarget { Type = typeof(TestClass), Member = method, ReturnedValueIsUsed = true };
			var result = measurableProperty.CalculateComplexity(target, IDE.VisualStudioOrSimilar);

			//Assert
			result.Should().Be(NumberOfParameters.ParameterComplexity);
			Console.WriteLine("Complexity of ctor = " + result);
		}

		[Test]
		public void No_suggestions_are_made_for_few_members()
		{
			//Arrange
			var measurableProperty = new NumberOfParameters();
			var method = typeof(TestClass).GetMember("FourInputParameters").First();

			//Act
			var target = new MeasurableTarget { Type = typeof(TestClass), Member = method, ReturnedValueIsUsed = true };
			var result = measurableProperty.GetSuggestions(target, IDE.VisualStudioOrSimilar);

			//Assert
			result.Should().BeEmpty();
		}

		[Test]
		public void Suggestion_is_made_for_too_many_members()
		{
			//Arrange
			var measurableProperty = new NumberOfParameters();
			var method = typeof(TestClass).GetMember("FiveInputParameters").First();

			//Act
			var target = new MeasurableTarget { Type = typeof(TestClass), Member = method, ReturnedValueIsUsed = true };
			var result = measurableProperty.GetSuggestions(target, IDE.VisualStudioOrSimilar).ToList();

			//Assert
			result.Should().HaveCount(1);
			Console.WriteLine(result.First());
		}

		[Test]
		public void Return_parameter_is_ignored_if_not_used()
		{
			//Arrange
			var measurableProperty = new NumberOfParameters();
			var method = typeof(TestClass).GetMember("SingleReturnParameter").First();

			//Act
			var target = new MeasurableTarget { Type = typeof(TestClass), Member = method, ReturnedValueIsUsed = false };
			var result = measurableProperty.CalculateComplexity(target, IDE.VisualStudioOrSimilar);

			//Assert
			result.Should().Be(0);
		}
	}
}
